﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Navigation;

using Microsoft.Phone.Controls;

using YourLastOptionsDialog.ViewModels.Options;

namespace YourLastOptionsDialog.ViewModels
{
    /// <summary>
    /// A view model for the options page that handles conversion of the options and basic setup work.
    /// </summary>
    public class OptionsPageViewModel : NavigationViewModelBase
    {
        private readonly ThreadedOptionConverter _converter = new ThreadedOptionConverter();
        private object _values;
        private string _title;
        private bool _isBusy;

        /// <summary>
        /// Gets or sets the title of the page.
        /// </summary>
        public string Title
        {
            get
            {
                return _title;
            }

            set
            {
                if (_title != value)
                {
                    _title = value;
                    RaisePropertyChanged("Title");
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the view model is busy with a conversion process.
        /// </summary>
        /// <value>
        ///   <c>true</c> if a conversion is in progress; otherwise, <c>false</c>.
        /// </value>
        public bool IsBusy
        {
            get
            {
                return _isBusy;
            }

            set
            {
                if (_isBusy != value)
                {
                    _isBusy = value;
                    RaisePropertyChanged("IsBusy");
                }
            }
        }

        /// <summary>
        /// Gets the option items to display in individual pivot items.
        /// </summary>
        public ObservableCollection<OptionsItemViewModel> OptionItems
        {
            get;
            private set;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="OptionsPageViewModel"/> class.
        /// </summary>
        public OptionsPageViewModel()
        {
            OptionItems = new ObservableCollection<OptionsItemViewModel>();
            _converter.Completed += Converter_Completed;
        }

        /// <summary>
        /// Raises the NavigatedTo event.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs" /> instance containing the event data.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (e == null)
            {
                return;
            }

            var values = OptionsService.Current.Values;

            if (e.NavigationMode == NavigationMode.Back)
            {
                // someone's navigating back to us => this means we are either activated 
                // or returned to from a subpage (e.g. ListPicker chooser page etc.).
                // first check whether the values in the Options are not equal null
                // if they're null the user of our library (desperately?) failed to restore
                // them after tombstoning => then there's no point in having an options dialog
                // (all edited values would be lost anyway) => perform a back navigation
                if (values == null)
                {
                    var frame = Application.Current.RootVisual as PhoneApplicationFrame;
                    if (frame != null && frame.CanGoBack)
                    {
                        try
                        {
                            frame.GoBack();
                        }
                        catch (Exception)
                        {
                            // ignore
                        }
                    }

                    return;
                }

                // now check to see whether we're just activated or return from tombstoning,
                // determined by the fact whether our values are null or different from the Options values
                if (_values != null && _values == values)
                {
                    // we're still working with the same data
                    // => reactivation without tombstoning
                    // => continue as if nothing happened :-)
                    return;
                }
            }

            // at this point we know we need to initialize
            // (clear the items to clean up in case we're returning after tombstoning and need to reinitialize)
            OptionItems.Clear();
            IsBusy = true;
            _values = values;
            _converter.StartConversion(_values);

            // try to get value from configuration
            Title = OptionsService.Current.Configuration.PageTitle;
        }

        private void Converter_Completed(object sender, OptionConversionEventArgs e)
        {
            // marshal the creation of UI elements back to the UI thread
            if (!Deployment.Current.CheckAccess())
            {
                Deployment.Current.Dispatcher.BeginInvoke(() => Converter_Completed(sender, e));
                return;
            }

            if (e.OptionGroups != null)
            {
                CreateItems(e.OptionGroups);
            }

            // signal that we're done
            IsBusy = false;
        }

        private void CreateItems(IEnumerable<OptionGroup> optionGroups)
        {
            OptionItems.Clear();

            foreach (var group in optionGroups)
            {
                // create view model
                var itemViewModel = new OptionsItemViewModel(group);
                OptionItems.Add(itemViewModel);
            }
        }
    }
}